package com.xdcplus.web.handler;


import cn.hutool.core.util.ObjectUtil;
import com.xdcplus.etl.schedule.annotation.Job;
import com.xdcplus.exceptions.XdcWebException;
import com.xdcplus.mom.pojo.vo.SysBaseDataVO;
import com.xdcplus.redis.RedisUtils;
import com.xdcplus.web.common.pojo.entity.trace.TracePacketBatchInfo;
import com.xdcplus.web.common.pojo.vo.trace.PacketShortInfoVO;
import com.xdcplus.web.common.pojo.vo.trace.PacketTraceInfoVO;
import com.xdcplus.web.component.CommonHelperService;
import com.xdcplus.web.service.CommonService;
import com.xdcplus.web.service.trace.PacketTraceWashService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Slf4j
@Component
public class PacketTraceWashHandler {

    @Value("${wash.isReversed: 0}")
    protected Integer isReversed;

    @Autowired
    private RedisUtils redisUtils;
    private final String WASH_KEY = "PACKET_BATCH_KEY";
    private final String WASH_KEY_SCHEDULE_LEVEL = "PACKET_BATCH_KEY_SCHEDULE_LEVEL";
    private final String WASH_KEY_LOCK = "PACKET_BATCH_KEY_LOCK";

    @Autowired
    protected PacketTraceWashService packetTraceWashService;

    @Autowired
    protected CommonService commonService;

    @Job("tracePacketBatchInfoHandle")
    public void washPacketBatchInfo() {

//        1、只按照小包中硅片过账信息关联质检批次，如果有多个批次的话取最多的那个
//        对外展示界面：
//        1、按照小包中硅片过账信息关联质检批次，如果有多个批次的话取最多的那个
//        2、如果1取不到，就按照分选线别取上一个有值的质检批次的小包（时间范围为一周），将该质检批次取过来
//        3、如果2取不到，就按照小包标签生成信息，往前倒推36小时，获取那个拆包计划的质检批次
//        增加小包与批次号对应关系表，可人工维护质检批次；
//        4、如果3找不到，就从线边库中的硅料来料时间推48小时，取最近的来料批次；
//        小包追溯接口和小包追溯功能数据结果一致；且小包追溯接口，增加箱号字段传递；


        try {
            Long lock = redisUtils.incrBy(WASH_KEY_LOCK, 1L);
            if (lock==null || lock != 1L) {
                throw new XdcWebException(-1,"未获取到锁");
            }
            try {
                log.info("已获取到锁");
                packetTrace();
            }catch (Exception e) {
                e.printStackTrace();
            }

            Long level = redisUtils.get(WASH_KEY_SCHEDULE_LEVEL, Long.class);
            if (level==null) {
                level = 1L;
            }
            level = Math.min(level,8L);
            level = Math.max(level,0L);
            redisUtils.set(WASH_KEY_SCHEDULE_LEVEL,level);
            Thread.sleep(BigDecimal.valueOf(Math.pow(2d,level*1d)).multiply(BigDecimal.valueOf(1000L)).longValue());

        }catch (Exception e) {
            e.printStackTrace();
        }


    }


    public void packetTrace() throws InterruptedException {

        boolean reverseBool = (isReversed == 1);

        List<PacketShortInfoVO> packetInfoList = packetTraceWashService.getPacketInfo(getLastId(), reverseBool);
        log.info("小包过账清洗,数量-{}",packetInfoList.size());
        if (ObjectUtil.isNotEmpty(packetInfoList)) {
            Long newPacketId = Collections.max(packetInfoList.stream().map(PacketShortInfoVO::getId).collect(Collectors.toList()));
            if (reverseBool) {
                newPacketId = Collections.min(packetInfoList.stream().map(PacketShortInfoVO::getId).collect(Collectors.toList()));
            }
            log.info("小包过账清洗，newlastid-{}", newPacketId);
            redisUtils.setEx(WASH_KEY,
                    newPacketId,
                    1L, TimeUnit.DAYS);
            redisUtils.incrBy(WASH_KEY_SCHEDULE_LEVEL,-1L);
        }else {
            redisUtils.incrBy(WASH_KEY_SCHEDULE_LEVEL,1L);
        }
        redisUtils.delete(WASH_KEY_LOCK);

        if (ObjectUtil.isNotEmpty(packetInfoList)) {

            Map<String, PacketShortInfoVO> packetDateMap = packetInfoList.stream().collect(
                    HashMap::new,
                    (map, item) -> map.put(item.getPacketCode(), item),
                    HashMap::putAll
            );

            List<String> packetCodes = packetInfoList.stream().map(PacketShortInfoVO::getPacketCode)
                    .distinct().collect(Collectors.toList());

            List<String> toolCodes = packetInfoList.stream().map(PacketShortInfoVO::getToolCode)
                    .distinct().collect(Collectors.toList());


            List<String> createdTimes = packetInfoList.stream()
                    .map(PacketShortInfoVO::getCreatedTime)
                    .map(v->v.toLocalDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                    .distinct().collect(Collectors.toList());

            Timestamp dateTime = Timestamp.from(Instant.now());


            Timestamp minTime = packetInfoList.stream().min(Comparator.comparing(PacketShortInfoVO::getCreatedTime)).get()
                    .getCreatedTime();

            Timestamp maxTime = packetInfoList.stream().max(Comparator.comparing(PacketShortInfoVO::getCreatedTime)).get()
                    .getCreatedTime();


            /// 查下小包追溯信息
            List<PacketTraceInfoVO> traceInfoByPacketCodes = packetTraceWashService.getTraceInfoByPacketCodes(
                    packetCodes, minTime, maxTime
            );

            Map<String, PacketTraceInfoVO> packetTraceInfoMap = traceInfoByPacketCodes.stream().collect(
                    HashMap::new,
                    (map, item) -> map.put(item.getPacketCode(), item),
                    HashMap::putAll
            );


            /// 同线别小包批次查下
            List<PacketTraceInfoVO> traceInfoByToolCodes = packetTraceWashService.getTraceInfoByToolCodes(
                    toolCodes, minTime, maxTime
            );

            Map<String, PacketTraceInfoVO> toolTraceInfoMap = traceInfoByToolCodes.stream().collect(
                    HashMap::new,
                    (map, item) -> map.put(item.getToolCode(), item),
                    HashMap::putAll
            );

            Integer unpackTimeRange = 36;
            SysBaseDataVO sysBaseDataByIdAndExt = commonService.getSysBaseDataByIdAndExt("TraceBatchParams", "unpackTimeRange");
            if (sysBaseDataByIdAndExt != null
                    && ObjectUtil.isNotEmpty(sysBaseDataByIdAndExt.getDataItem())) {
                unpackTimeRange = Integer.parseInt(sysBaseDataByIdAndExt.getDataItem());
            }

            List<PacketTraceInfoVO> traceInfoByCreatedTime = new ArrayList<>();
            for (String createdTime : createdTimes) {
                PacketTraceInfoVO traceInfoByCreatedTime1 = packetTraceWashService.getTraceInfoByCreatedTime(
                        createdTime, minTime, maxTime,unpackTimeRange
                );
                if (traceInfoByCreatedTime1 != null) {
                    traceInfoByCreatedTime.add(
                            traceInfoByCreatedTime1
                    );
                }
            }
            Map<String, PacketTraceInfoVO> unpackTraceInfoMap = traceInfoByCreatedTime.stream().collect(
                    HashMap::new,
                    (map, item) -> map.put(item.getCreatedTime().toLocalDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), item),
                    HashMap::putAll
            );


            Integer mtrlTimeRange = 48;
            sysBaseDataByIdAndExt = commonService.getSysBaseDataByIdAndExt("TraceBatchParams", "mtrlTimeRange");
            if (sysBaseDataByIdAndExt != null
                && ObjectUtil.isNotEmpty(sysBaseDataByIdAndExt.getDataItem())) {
                mtrlTimeRange = Integer.parseInt(sysBaseDataByIdAndExt.getDataItem());
            }

            List<PacketTraceInfoVO> meterialOrderByCreatedTime = new ArrayList<>();
            for (String createdTime : createdTimes) {
                PacketTraceInfoVO meterialOrderByCreatedTime1 = packetTraceWashService.getMeterialOrderByCreatedTime(
                        createdTime, minTime, maxTime,mtrlTimeRange
                );
                if (meterialOrderByCreatedTime1 != null) {
                    meterialOrderByCreatedTime.add(
                            meterialOrderByCreatedTime1);
                }
            }

            Map<String, PacketTraceInfoVO> meterialTraceInfoMap = meterialOrderByCreatedTime.stream().collect(
                    HashMap::new,
                    (map, item) -> map.put(item.getCreatedTime().toLocalDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), item),
                    HashMap::putAll
            );


            List<TracePacketBatchInfo> tracePacketBatchInfos = new ArrayList<>();

            for (String code : packetCodes) {

                TracePacketBatchInfo tracePacketBatchInfo = new TracePacketBatchInfo();
                tracePacketBatchInfo.setPacketCode(code);
                PacketShortInfoVO packetShortInfoVO = packetDateMap.get(code);
                tracePacketBatchInfo.setPacketDateTime(packetShortInfoVO.getCreatedTime());
                tracePacketBatchInfo.setPacketId(packetShortInfoVO.getId());
                tracePacketBatchInfo.setWashDateTime(dateTime);

                if (packetTraceInfoMap.containsKey(code)) {
                    PacketTraceInfoVO packetTraceInfoVO = packetTraceInfoMap.get(code);
                    tracePacketBatchInfo.setBatchCodeOne(packetTraceInfoVO.getBatchCode());
                    tracePacketBatchInfo.setWoCodeOne(packetTraceInfoVO.getWoCode());
                }


                String toolCode = packetShortInfoVO.getToolCode();
                if (toolTraceInfoMap.containsKey(toolCode)) {
                    PacketTraceInfoVO packetTraceInfoVO2 = toolTraceInfoMap.get(toolCode);
                    tracePacketBatchInfo.setBatchCodeTwo(packetTraceInfoVO2.getBatchCode());
                    tracePacketBatchInfo.setWoCodeTwo(packetTraceInfoVO2.getWoCode());
                }


                String createdTime = packetShortInfoVO.getCreatedTime()
                        .toLocalDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                if (unpackTraceInfoMap.containsKey(createdTime)) {
                    PacketTraceInfoVO packetTraceInfoVO1 = unpackTraceInfoMap.get(createdTime);
                    tracePacketBatchInfo.setBatchCodeThree(packetTraceInfoVO1.getBatchCode());
                    tracePacketBatchInfo.setWoCodeThree(packetTraceInfoVO1.getWoCode());
                    tracePacketBatchInfo.setUnpackPlanCode(packetTraceInfoVO1.getUnpackPlanCode());
                }


                if (meterialTraceInfoMap.containsKey(createdTime)) {
                    PacketTraceInfoVO meterialTraceInfoVO = meterialTraceInfoMap.get(createdTime);

                    tracePacketBatchInfo.setBatchCodeFour(meterialTraceInfoVO.getBatchCode());
                    tracePacketBatchInfo.setWoCodeFour(meterialTraceInfoVO.getWoCode());
                }


                tracePacketBatchInfos.add(tracePacketBatchInfo);

            }
            log.info("小包过账清洗，结果-{}",tracePacketBatchInfos.size());
            packetTraceWashService.saveBatch(tracePacketBatchInfos);

        }

        Thread.sleep(10L);


    }

    private Long getLastId() {
        Long id = redisUtils.get(WASH_KEY,Long.class);
        if (ObjectUtil.isNull(id)) {
            id = packetTraceWashService.getLastPacketId();
        }
        if (ObjectUtil.isNull(id)) {
            id = 0L;
        }
        log.info("小包过账清洗，lastid-{}",id);
        return id;
    }



}
